/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.editpart;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.ReconnectRequest;
import org.eclipse.ui.PlatformUI;

import com.cea.papyrus.core.commands.connection.ConnectionCreateCommand;
import com.cea.papyrus.core.commands.connection.ConnectionReconnectCommand;
import com.cea.papyrus.core.commands.factories.ConnectionCreateCommandFactory;
import com.cea.papyrus.core.commands.factories.ConnectionReconnectCommandFactory;
import com.cea.papyrus.core.editor.DiagramEditorPage;
import com.cea.papyrus.core.editor.MultiDiagramEditor;
import com.cea.papyrus.core.editpart.connection.AnchorableGraphEdgeEditPart;
import com.cea.papyrus.core.editpart.connection.AnchorableGraphNodeEditPart;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.core.pseudoelement.EnhancedType;
import com.cea.papyrus.core.pseudoelement.UMLElementFactory;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

/**
 * Install Connection creation/destruction/move EditPolicy
 */
public class GraphNodeEditPolicy extends GraphicalNodeEditPolicy {
	/* 
	 * End creation of the connection. The previous command is retrieved
	 * and the target is set.
	 */
	/**
	 * 
	 * 
	 * @param request 
	 * 
	 * @return 
	 */
	@Override
	protected Command getConnectionCompleteCommand(CreateConnectionRequest request) {
		ConnectionCreateCommand cmd 
		= (ConnectionCreateCommand) request.getStartCommand();

		if (!(getHost().getModel() instanceof GraphNode)) {
			return cmd;
		}
		//Darpan
//		MultiDiagramEditor mde
//		=(MultiDiagramEditor) PlatformUI
//		.getWorkbench()
//		.getActiveWorkbenchWindow()
//		.getActivePage()
//		.getActiveEditor();
//		DiagramEditorPage cde=(DiagramEditorPage)mde.getActiveEditor();

		cmd.setParent((GraphNode)((GraphNode) getHost().getModel()).getContainer());
		Point location = computeAnchorLocation(request.getLocation(), getHost());
		cmd.setTarget((GraphNode) getHost().getModel(), location);
		return cmd;
	}

	/* 
	 * Start creation of a connection. The Command is created, and the src is set.
	 */
	/**
	 * 
	 * 
	 * @param request 
	 * 
	 * @return 
	 */
	@Override
	protected Command getConnectionCreateCommand(CreateConnectionRequest request) {

		Class type;
		Object newObjectDescription 
		= EnhancedType.getNewObjectDescription(request);

		if (!(getHost().getModel() instanceof GraphNode)) {
			return null;
		}

		GraphNode source        = (GraphNode) getHost().getModel();
		GraphElement container  = source.getContainer();

		// Test creation restriction in Connector creation
		// (due to filters defined in PaletteMenu extension
		boolean noRestriction = true;
		if (newObjectDescription instanceof UMLElementFactory) {
			UMLElementFactory enhancedType = (UMLElementFactory) newObjectDescription;
			type          = enhancedType.getClazz();
			noRestriction = enhancedType.canExecute(source);
		} else {
			type = (Class)  newObjectDescription;
		}

		/*if((!(container instanceof Diagram))
				&&	(container.getSemanticModel() == null)) {
			// the source dont have to be a property for instance.
			return null; 
		}*/

		Point location = computeAnchorLocation(request.getLocation(), getHost());

		if(source.getSemanticModel()!=null&&
				ModelerHelper.getFactory().canConnect( type,((Uml1SemanticModelBridge)source.getSemanticModel()).getElement(), null) && noRestriction) {
			ConnectionCreateCommand cmd = getConnectionCreateCommandFactory().getConnectionCreateCommand(source, newObjectDescription, location);
			request.setStartCommand(cmd);
			return cmd;
		}
		return null;
	}

	/**
	 * Get the ConnectionCreateCommandFactory.
	 * This method can be overloaded by subclasses in order to provide specific factory.
	 * @return
	 */
	protected ConnectionCreateCommandFactory getConnectionCreateCommandFactory()
	{
	    return ConnectionCreateCommandFactory.eINSTANCE;
	}
	
	/**
	 * Compute the anchor location for the provided position and editPart.
	 * 
	 * @param editPart 
	 * @param reference 
	 * 
	 * @return 
	 */
	protected Point computeAnchorLocation(Point reference, EditPart editPart)
	{
//		First, translate the reference to the coordinate of the diagram (like shape constraints).
		IFigure parentFigure = ((GraphicalEditPart)editPart).getFigure();
		Point res = reference.getCopy();
		parentFigure.translateToRelative(res);
		if(editPart instanceof AnchorableGraphNodeEditPart )
			return ((AnchorableGraphNodeEditPart)editPart).getAnchorMngr().getRelativeAnchorPosition(res);
		if(editPart instanceof AnchorableGraphEdgeEditPart )
			return ((AnchorableGraphEdgeEditPart)editPart).getAnchorMngr().getRelativeAnchorPosition(res);
		return reference;
	}



	/* 
	 * Returns the <code>Command</code> to reconnect a connection's <i>source</i> end to the
	 * host.
	 */
	/**
	 * 
	 * 
	 * @param request 
	 * 
	 * @return 
	 */
	@Override
	protected Command getReconnectSourceCommand(ReconnectRequest request) {
		if (!(getHost().getModel() instanceof GraphNode)) {
			return null;
		}

		GraphEdge connector = (GraphEdge) request.getConnectionEditPart().getModel();
		GraphNode newSource = (GraphNode) getHost().getModel();

		Point location = computeAnchorLocation(request.getLocation(), getHost());
		
		ConnectionReconnectCommand cmd = ConnectionReconnectCommandFactory.eINSTANCE.getConnectionReconnectCommand(connector, newSource, location, ConnectionReconnectCommand.SOURCE); 
		return cmd;
	}
	/* 
	 * Returns the <code>Command</code> to reconnect a connection's <i>target</i> end to the
	 * host.
	 */
	/**
	 * 
	 * 
	 * @param request 
	 * 
	 * @return 
	 */
	@Override
	protected Command getReconnectTargetCommand(ReconnectRequest request) {
		if (!(getHost().getModel() instanceof GraphNode)) {
			return null;
		}

		GraphEdge connector = (GraphEdge) request.getConnectionEditPart().getModel();
		GraphNode newTarget = (GraphNode) getHost().getModel();

		Point location = computeAnchorLocation(request.getLocation(), getHost());
		ConnectionReconnectCommand cmd = ConnectionReconnectCommandFactory.eINSTANCE.getConnectionReconnectCommand(connector, newTarget, location, ConnectionReconnectCommand.TARGET); 
		
		return cmd;
	}
}
